package com.swak.job.worker;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;

import org.springframework.scheduling.support.CronExpression;

import com.swak.job.Job;
import com.swak.job.JobConfig;
import com.swak.job.JobTask;
import com.swak.job.enums.Role;
import com.swak.job.exception.JobException;
import com.swak.job.queue.QueueService;
import com.swak.job.storage.StorageService;
import com.swak.job.timer.Timer;
import com.swak.job.timer.Timer.CronTrigger;
import com.swak.job.timer.TimerTask.TaskFrag;
import com.swak.leader.LeaderService;
import com.swak.metrics.MetricsFactory;
import com.swak.registry.RegistryService;
import com.swak.registry.URL;
import com.swak.utils.time.DateTimes;

/**
 * 重试
 * 
 * @author DELL
 */
@Deprecated
public class RetryWorker extends LeaderAbstractWorker {

	protected final StorageService storageService;

	private long retryMillisSeconds = 180 * 1000;
	private String cronExpression;
	private CronExpression cronSequenceGenerator;

	/**
	 * 执行器
	 */
	private Timer timer;
	private CronTrigger cronTrigger;

	public RetryWorker(Timer timer, JobConfig config, Job job, StorageService storageService, QueueService queueService,
			RegistryService registryService, LeaderService leaderService, MetricsFactory metricsFactory) {
		super(config, Role.Retryer, job, queueService, registryService, leaderService, metricsFactory);
		this.storageService = storageService;
		this.timer = timer;
	}

	@Override
	protected void doRefresh() {
		super.doRefresh();
		this.cronExpression = this.getRefreshAbleCronExpression();
		this.cronSequenceGenerator = CronExpression.parse(this.cronExpression);
		LocalDateTime todayDate = DateTimes.now();
		this.retryMillisSeconds = DateTimes.getMilliByTime(this.cronSequenceGenerator.next(todayDate))
				- DateTimes.getMilliByTime(todayDate);
	}

	@Override
	public void start() {
		super.start();
		this.cronTrigger = this.timer.scheduleTasks(job.getName(), this.cronExpression, false, this::doTask);
	}

	/**
	 * 执行定时任务
	 * 
	 * @param frag
	 * @return
	 */
	private Object doTask(final TaskFrag frag) {
		if (this.opened && this.isLeader()) {
			return this.doRetry(frag);
		}
		return null;
	}

	/**
	 * 让代码包裹的代码在 指定的线程中执行
	 * 
	 * @param frag
	 * @return
	 */
	protected Object doRetry(final TaskFrag frag) {
		try {
			return this.invoke(() -> {
				this.doInnerRetry(frag);
			});
		} catch (Throwable e) {
			throw new JobException(e);
		}
	}

	protected void doInnerRetry(TaskFrag frag) {
		Object metrics = this.namedMetrics != null ? this.namedMetrics.begin() : null;
		boolean success = true;
		try {
			// Date delayDate = new Date(System.currentTimeMillis() - retryMillisSeconds);
			LocalDateTime delayDate = DateTimes.minu(DateTimes.now(), retryMillisSeconds, ChronoUnit.MILLIS);
			List<JobTask> tasks = this.storageService.queryFailTasks(delayDate);
			if (logger.isDebugEnabled()) {
				logger.debug("Job {} 需要重试 {} Tasks.", this.job.getName(), tasks.size());
			}

			for (JobTask task : tasks) {
				try {
					URL url = URL.valueOf(task.getExecuteUrl());
					String queue = this.queueService.parseExecuteQueue(url);
					this.queueService.publishQueue(queue, task);
				} catch (Throwable e) {
					logger.debug("Job {} 重试失败", this.job.getName(), e);
				}
			}
		} catch (Exception e) {
			success = false;
		} finally {
			if (this.namedMetrics != null) {
				this.namedMetrics.end(metrics, success);
			}
		}
	}

	@Override
	public void stop() {
		super.stop();
		if (this.cronTrigger != null) {
			this.cronTrigger.cancel();
		}
	}
}
